/*
-----------------------------------------------------------------------------
Filename:    BaseApplication.cpp
-----------------------------------------------------------------------------


-----------------------------------------------------------------------------
*/
#include "BaseApplication.h"



//-------------------------------------------------------------------------------------
BaseApplication::BaseApplication(void)
	: mRoot(0),
	mCamera1(0),
	mCamera2(0),
	mSceneMgr(0),
	mWindow(0),
	mResourcesCfg(Ogre::StringUtil::BLANK),
	mPluginsCfg(Ogre::StringUtil::BLANK),
	mCursorWasVisible(false),
	mShutDown(false),
	mInputManager(0),
	mMouse(0),
	mKeyboard(0)
{
}

//-------------------------------------------------------------------------------------
BaseApplication::~BaseApplication(void)
{
	//Remove ourself as a Window listener
	Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
	windowClosed(mWindow);

	if( mInputManager ) {
        if( mMouse ) {
            mInputManager->destroyInputObject( mMouse );
            mMouse = 0;
        }
 
        if( mKeyboard ) {
            mInputManager->destroyInputObject( mKeyboard );
            mKeyboard = 0;
        }
 
        // If you use OIS1.0RC1 or above, uncomment this line
        // and comment the line below it
        mInputManager->destroyInputSystem( mInputManager );
        //mInputSystem->destroyInputSystem();
        mInputManager = 0;
 
        // Clear Listeners
    }



	delete mRoot;
}

//-------------------------------------------------------------------------------------
bool BaseApplication::configure(void)
{
	// Show the configuration dialog and initialise the system
	// You can skip this and use root.restoreConfig() to load configuration
	// settings if you were sure there are valid ones saved in ogre.cfg
	if(mRoot->restoreConfig() || mRoot->showConfigDialog())
	{
		// If returned true, user clicked OK so initialise
		// Here we choose to let the system create a default rendering window by passing 'true'
		mWindow = mRoot->initialise(true, "SpaceProject Game");

		return true;
	}
	else
	{
		gameLog->logMessage("Configuration dialog cancelled.");
		return false;
	}
}
//-------------------------------------------------------------------------------------
void BaseApplication::chooseSceneManager(void)
{
	// Get the SceneManager, in this case a generic one
	mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);
}
//-------------------------------------------------------------------------------------
void BaseApplication::createCamera(void)
{
	// Create the camera
	mCamera1 = mSceneMgr->createCamera("Player1Cam");
	mCamera2 = mSceneMgr->createCamera("Player2Cam");

	// Create the camera for map navigation:
	mCameraNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNodeFree", Ogre::Vector3(0, 200, 300));
	mCameraNode->attachObject(mCamera1);
	mCameraNode->attachObject(mCamera2);
	
	mCamera1->lookAt(Ogre::Vector3(0,20,0));
	mCamera1->setNearClipDistance(5);
	mCamera2->lookAt(Ogre::Vector3(0,20,0));
	mCamera2->setNearClipDistance(5);

	mCameraDirection = Ogre::Vector3::ZERO;
	mCameraMove = 30;

}
//-------------------------------------------------------------------------------------
void BaseApplication::createFrameListener(void)
{
	Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
	OIS::ParamList pl;
	size_t windowHnd = 0;
	std::ostringstream windowHndStr;

	mWindow->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

	mInputManager = OIS::InputManager::createInputSystem( pl );

	mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, true ));
	mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));

	mMouse->setEventCallback(this);
	mKeyboard->setEventCallback(this);

	//Set initial mouse clipping size
	windowResized(mWindow);

	//Register as a Window listener
	Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);


	mRoot->addFrameListener(this);
}
//-------------------------------------------------------------------------------------
void BaseApplication::destroyScene(void)
{
}
//-------------------------------------------------------------------------------------
void BaseApplication::createViewports(void)
{
	// Create one viewport, entire window
	Ogre::Viewport* vp = mWindow->addViewport(mCamera1);
	vp->setBackgroundColour(Ogre::ColourValue(0,0,0));

	// Alter the camera aspect ratio to match the viewport
	mCamera1->setAspectRatio( Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()) );
}

//-------------------------------------------------------------------------------------
void BaseApplication::setupResources(void)
{
	// Load resource paths from config file
	Ogre::ConfigFile cf;
	cf.load(mResourcesCfg);

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
			archName, typeName, secName);
		}
	}
}
//-------------------------------------------------------------------------------------
void BaseApplication::createResourceListener(void){}
//-------------------------------------------------------------------------------------
void BaseApplication::loadResources(void)
{
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
//-------------------------------------------------------------------------------------
void BaseApplication::go(void)
{
#ifdef _DEBUG
	mResourcesCfg = "resources_d.cfg";
	mPluginsCfg = "plugins_d.cfg";
#else
	mResourcesCfg = "resources.cfg";
	mPluginsCfg = "plugins.cfg";
#endif

	if (!setup())
		return;

	gameLog->logMessage("Init complete!");
	mRoot->startRendering();
	gameLog->logMessage("Exiting!");
	// clean up
	destroyScene();
}
//-------------------------------------------------------------------------------------
bool BaseApplication::setup(void)
{
	// Creamos el LogManager
	mLog = new Ogre::LogManager;

	// Log systems:
	systemLog = mLog->createLog("systemLog.log", true, false, false);
	gameLog   = mLog->createLog("gameLog.log", false, true, false);

	mRoot = new Ogre::Root(mPluginsCfg);

	setupResources();

	bool carryOn = configure();
	if (!carryOn) return false;

	chooseSceneManager();
	createCamera();
	createViewports();

	// Set default mipmap level (NB some APIs ignore this)
	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);

	// Create any resource listeners (for loading screens)
	createResourceListener();
	// Load resources
	loadResources();

	// Create the scene
	createScene();

	createFrameListener();

	return true;
};
//-------------------------------------------------------------------------------------
bool BaseApplication::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	if(mWindow->isClosed())
		return false;

	if(mShutDown)
		return false;

	//Need to capture/update each device
	mKeyboard->capture();
	mMouse->capture();

	// movimiento del nodo camara
	mCameraNode->translate(mCameraDirection * evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL);

	return true;
}
//-------------------------------------------------------------------------------------
bool BaseApplication::keyPressed( const OIS::KeyEvent &arg )
{
	
	switch (arg.key)
    	{
	case OIS::KC_UP:
	//case OIS::KC_W:
	    mCameraDirection.z = -mCameraMove;
	    break;
 
	case OIS::KC_DOWN:
	//case OIS::KC_S:
	    mCameraDirection.z = mCameraMove;
	    break;
 
	case OIS::KC_LEFT:
	//case OIS::KC_A:
	    mCameraDirection.x = -mCameraMove;
	    break;
 
	case OIS::KC_RIGHT:
	//case OIS::KC_D:
	    mCameraDirection.x = mCameraMove;
	    break;
 
	case OIS::KC_PGDOWN:
	//case OIS::KC_E:
	    mCameraDirection.y = -mCameraMove;
	    break;
 
	case OIS::KC_PGUP:
	//case OIS::KC_Q:
	    mCameraDirection.y = mCameraMove;
	    break;
    }

	return true;
}

bool BaseApplication::keyReleased( const OIS::KeyEvent &arg )
{
	switch (arg.key)
	{
	case OIS::KC_UP:
	//case OIS::KC_W:
	    mCameraDirection.z = 0;
	    break;
	 
	case OIS::KC_DOWN:
	//case OIS::KC_S:
	    mCameraDirection.z = 0;
	    break;
	 
	case OIS::KC_LEFT:
	//case OIS::KC_A:
	    mCameraDirection.x = 0;
	    break;
	 
	case OIS::KC_RIGHT:
	//case OIS::KC_D:
	    mCameraDirection.x = 0;
	    break;
	 
	case OIS::KC_PGDOWN:
	//case OIS::KC_E:
	    mCameraDirection.y = 0;
	    break;
	 
	case OIS::KC_PGUP:
	//case OIS::KC_Q:
	    mCameraDirection.y = 0;
	    break;
	default:
	    break;
	}
	
	return true;
}

bool BaseApplication::mouseMoved( const OIS::MouseEvent &arg )
{

	return true;
}

bool BaseApplication::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{

	return true;
}

bool BaseApplication::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{

	return true;
}

//Adjust mouse clipping area
void BaseApplication::windowResized(Ogre::RenderWindow* rw)
{
	unsigned int width, height, depth;
	int left, top;
	rw->getMetrics(width, height, depth, left, top);

	const OIS::MouseState &ms = mMouse->getMouseState();
	ms.width = width;
	ms.height = height;
}

//Unattach OIS before window shutdown (very important under Linux)
void BaseApplication::windowClosed(Ogre::RenderWindow* rw)
{
    //Only close for window that created OIS (the main window in these demos)
	if( rw == mWindow )
	{
		if( mInputManager )
		{
			mInputManager->destroyInputObject( mMouse );
			mInputManager->destroyInputObject( mKeyboard );

			OIS::InputManager::destroyInputSystem(mInputManager);
			mInputManager = 0;
		}
	}
}
